package core.source.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;

import core.config.exception.CloudException;
import core.source.pojo.dto.PorjectDTO;
import core.source.pojo.entity.Column;
import core.source.pojo.entity.Library;
import core.source.pojo.entity.Porject;
import core.source.pojo.entity.Table;
import core.source.service.SourceService;
import core.utils.FileUtils;
import core.utils.StrUtils;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * @author Long
 * @version 1.0
 * @description:
 * @title SourceServiceImpl
 * @date 2021/3/6 9:58
 */
public class SourceServiceImpl implements SourceService {

    @Override
    public List<Map<String, Object>> getData(Porject porject, DatabaseMetaData metaData, String libraryName) {
        return this.getData(porject, this.getLibrary(metaData, libraryName));
    }

    @Override
    public List<Map<String, Object>> getData(Porject porject, Library library) {
        List<Table> tables = library.getTables();
        library.setTables(null);

        return new ArrayList<>(){{
            tables.forEach((table -> {
                Map<String, Object> map = new HashMap<>();
                map.putAll(BeanUtil.beanToMap(table));
                map.putAll(BeanUtil.beanToMap(library));
                map.putAll(BeanUtil.beanToMap(porject));
                this.add(map);
            }));
        }};
    }

    @Override
    public Porject getPorject(PorjectDTO dto) {
        Porject porject = new Porject();
        BeanUtil.copyProperties(dto, porject);
        String[] paths = porject.getPackageName().split("\\.");
        porject.setFirstPackage(paths[0]);
        porject.setSecondPackage(paths.length>1?paths[1]:porject.getSecondPackage());
        porject.setThirdPackage(paths.length>2?paths[2]:porject.getThirdPackage());
        return porject;
    }

    @Override
    public List<Library> getLibrarys(DatabaseMetaData metaData) {
        try {
            ResultSet resultSet = metaData.getCatalogs();
            return new ArrayList<>() {{
                while (resultSet.next()) {
                    Library library = getLibrary(resultSet);
                    this.add(getLibrary(metaData, library));
                }
            }};
        } catch (SQLException throwables) {
            throw new CloudException("库信息获取失败");
        }
    }

    @Override
    public List<Library> getLibrarys(DatabaseMetaData metaData, String[] libraryNames) {
        if (StrUtil.isAllBlank(libraryNames)) {
            return this.getLibrarys(metaData);
        }
        return new ArrayList<>(){{
            for (String libraryName : libraryNames) {
                this.add(getLibrary(metaData, libraryName));
            }
        }};
    }

    @Override
    public Library getLibrary(DatabaseMetaData metaData, String libraryName) {
        try {
            ResultSet resultSet = metaData.getCatalogs();
            while (resultSet.next()) {
                Library library = this.getLibrary(resultSet);
                if (library.getLibraryName().equals(libraryName)) {
                    return getLibrary(metaData, library);
                }
            }
            return null;
        } catch (SQLException throwables) {
            throw new CloudException("数据库获取异常2");
        }
    }

    @Override
    public Library getLibrary(DatabaseMetaData metaData, Library library) {
        try {
            library.setHumpLibraryName(StrUtils.lineToHump(library.getLibraryName()));
            library.setUsername(metaData.getUserName());
            library.setLibraryVersion(metaData.getDatabaseProductVersion());
            library.setTables(getTables(metaData));
            return library;
        } catch (SQLException throwables) {
            throw new CloudException("数据库获取异常3");
        }
    }

    @Override
    public Library getLibrary(ResultSet resultSet) {
        try {
            Library library = new Library();
            library.setLibraryName(resultSet.getString(1));
            return library;
        } catch (SQLException throwables) {
            throw new CloudException("数据库获取异常4");
        }
    }

    @Override
    public List<Table> getTables(DatabaseMetaData metaData) {
        ResultSet resultSet = this.getTableResultSet(metaData, "");
        return this.getTables(metaData, resultSet);
    }


    @Override
    public List<Table> getTables(DatabaseMetaData metaData, String[] tableNames) {
        return new ArrayList<>() {{
            for (String tableName : tableNames) {
                this.add(getTable(metaData, tableName));
            }
        }};
    }

    @Override
    public List<Table> getTables(DatabaseMetaData metaData, ResultSet resultSet) {
        try {
            return new ArrayList<>() {{
                while (resultSet.next()) {
                    Table table = getTable(resultSet);
                    table.setColumns(getColumns(metaData, table.getTableName()));
                    table.getColumns().forEach(column -> {
                        if ("PRI".equals(column.getPrimaryKey())) {
                            table.setTablePrimaryKeyType(column.getJavaType());
                        }
                    });
                    this.add(table);
                }
            }};
        } catch (SQLException throwables) {
            throw new CloudException("表获取异常");
        }
    }

    @Override
    public Table getTable(DatabaseMetaData metaData, String tableName) {
        ResultSet resultSet = this.getTableResultSet(metaData, tableName);
        Table table = this.getTable(resultSet);
        table.setColumns(this.getColumns(metaData, tableName));
        return table;
    }

    @Override
    public List<Column> getColumns(ResultSet resultSet, String keys) {
        try {
            return new ArrayList<>() {{
                while (resultSet.next()) {
                    this.add(getColumn(resultSet, keys));
                }
            }};
        } catch (SQLException throwables) {
            throw new CloudException("列获取异常");
        }
    }


    @Override
    public List<Column> getColumns(DatabaseMetaData metaData, String tableName) {
        ResultSet resultSet = this.getColumnResultSet(metaData, tableName);
        return this.getColumns(resultSet, getKeys(metaData, tableName));
    }

    @Override
    public Table getTable(ResultSet resultSet) {
        try {
            Table table = new Table();
            table.setTableName(resultSet.getString("TABLE_NAME"));
            table.setTableCat(resultSet.getString("TABLE_CAT"));
            table.setTableSchem(resultSet.getString("TABLE_SCHEM"));
            table.setTableType(resultSet.getString("TABLE_TYPE"));
            table.setTableRremarks(resultSet.getString("REMARKS"));
            return this.getTable(table);
        } catch (SQLException throwables) {
            throw new CloudException("表获取异常2");
        }
    }

    @Override
    public Table getTable(Table table) {
        table.setHumpTableName(StrUtils.lineToHump(table.getTableName()));
        String str = table.getHumpTableName();
        table.setEntityName(str.substring(0,1).toUpperCase()+str.substring(1));
        table.setLowerCaseTableName(table.getTableName().replaceAll("_", "").toLowerCase());
        return table;
    }

    @Override
    public ResultSet getTableResultSet(DatabaseMetaData metaData, String tableName) {
        try {
            return metaData.getTables(null, null, tableName, new String[]{"TABLE"});
        } catch (SQLException throwables) {
            throw new CloudException("表数据加载异常");
        }
    }

    @Override
    public ResultSet getColumnResultSet(DatabaseMetaData metaData, String tableName) {
        try {
            return metaData.getColumns(null, null, tableName, null);
        } catch (SQLException throwables) {
            throw new CloudException("列数据加载异常");
        }
    }

    @Override
    public String getKeys(DatabaseMetaData metaData, String tableName) {
        try {
            ResultSet primaryKeys = metaData.getPrimaryKeys(null, null, tableName);
            String keys = "";
            while (primaryKeys.next()) {
                String keyname = primaryKeys.getString("COLUMN_NAME");
                keys += keyname + ",";
            }
            return keys;
        } catch (SQLException throwables) {
            throw new CloudException("key列获取异常");
        }
    }

    @Override
    public Column getColumn(ResultSet resultSet, String keys) {
        try {
            Column column = new Column();
            column.setColumnName(resultSet.getString("COLUMN_NAME"));
            column.setDataType(resultSet.getString("TYPE_NAME"));
            column.setRemarks(resultSet.getString("REMARKS"));
            column.setNullAble(resultSet.getString("NULLABLE"));
            column.setDecimalDifits(resultSet.getString("DECIMAL_DIGITS"));
            column.setDataSize(resultSet.getString("COLUMN_SIZE"));

            if (StrUtils.contains(column.getColumnName(), keys.split(","))) {
                column.setPrimaryKey("PRI");
            }
            return this.getColumn(column);
        } catch (SQLException throwables) {
            throw new CloudException("列数据加载异常2");
        }
    }


    @Override
    public Column getColumn(Column column) {
        column.setHumpName(StrUtils.lineToHump(column.getColumnName()));
        column.setLowerCaseTableName(column.getHumpName().toLowerCase());
        column.setUpperCaseName(column.getHumpName().toUpperCase());
        column.setJavaType(this.getProperties().get(column.getDataType()));
        return column;
    }

    @Override
    public Map<String, String> getProperties() {
        return this.getProperties("/config/properties/");
    }

    @Override
    public Map<String, String> getProperties(String path) {
        try {
            List<File> files = FileUtils.searchAllFile(new File(this.getClass().getResource(path).getPath()));
            return new HashMap<>() {{
                for (File file : files) {
                    if (file.getName().endsWith(".properties")) {
                        Properties prop = new Properties();
                        prop.load(new FileInputStream(file));
                        this.putAll((Map) prop);
                    }
                }
            }};
        } catch (IOException e) {
            throw new CloudException("配置数据加载异常");
        }
    }
}
